#include "BinaryToBase64.h"

/* Toma de 1 a 3 bytes binarios y los transforma en 4 en base 64 */
void toBase64(const unsigned char* bytes, int length, char* result) {

	uint32_t number; /* Numero de 24 bits creado a partir de los bytes de entrada */
	uint32_t n[4]; /* Para separar el numero de 24 bits en 4 numeros de 6 bits */

	/* Convertir los 3,2 o 1 bytes en un numero de 24 bits */

	/* Si tengo 1, 2 o 3 bytes */
	number = bytes[0] << 16;

	if (length >= 2) { /*Si tengo 2 o 3 bytes */
		number += bytes[1] << 8;
	}

	if (length == 3) { /* Si tengo 3 bytes */
		number += bytes[2];
	}

	n[0] = (uint8_t) (number >> 18) & 63;
	n[1] = (uint8_t) (number >> 12) & 63;
	n[2] = (uint8_t) (number >> 6) & 63;
	n[3] = (uint8_t) number & 63;

	/* Si tengo 1 byte, me salen 2 convertidos y 2 de pad*/
	if (length == 1) {
		result[0] = ALPHABET[n[0]];
		result[1] = ALPHABET[n[1]];
	}

	/* Si tengo 2 bytes, me salen 3 convertidos y 1 de pad*/
	if (length == 2) {
		result[0] = ALPHABET[n[0]];
		result[1] = ALPHABET[n[1]];
		result[2] = ALPHABET[n[2]];
	}

	/* Si tengo 3 bytes, me salen 4 convertidos*/
	if (length == 3) {
		result[0] = ALPHABET[n[0]];
		result[1] = ALPHABET[n[1]];
		result[2] = ALPHABET[n[2]];
		result[3] = ALPHABET[n[3]];
	}
}

int binaryToBase64(FILE* input, FILE* output) {
	fflush(output);
	int counter = 0; /* Cuenta cada byte que lee */
	int c = fgetc(input);
	checkReadError(input);
	unsigned char buffer[3]; /* En este buffer acumulamos 3 bytes. El 4to es para fin de string */
	char tmpResult[5];

	while (1) {
		/* Se limpia el resultado temporal */
		memset(tmpResult, '=', 4);
		tmpResult[4] = 0;

		counter++;
		if (c == EOF) { /* Cuando llego al EOF convierto los bytes que acumule (si es que tengo alguno) */
			counter--; /* Resto uno para que no me cuente el EOF como caracter */
			if (counter > 0) {
				toBase64(buffer, counter,tmpResult);
				fputs(tmpResult, output);
				checkWriteError(output);
			}
			break;
		} else {
			buffer[counter - 1] = c; /* Acumulo el byte en el array */
			if (counter == 3) { /* Ya tengo 3 bytes, lo convierto */
				toBase64(buffer, counter, tmpResult);
				fputs(tmpResult, output);
				checkWriteError(output);
				counter = 0;
			}
		}
		c = fgetc(input);
		checkReadError(input);
	}

	//Devuelve un 0 si no hubo errores
	return EXIT_SUCCESS;
}
